home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
dfue
/
elcheapofax
/
faxcmd
/
libfax
/
rcs
/
tty.c,v
< prev
next >
Wrap
Text File
|
1995-03-09
|
13KB
|
630 lines
head 1.3;
access;
symbols
OCT93:1.3;
locks;
comment @ * @;
1.3
date 93.07.13.05.41.27; author Rhialto; state Exp;
branches;
next 1.2;
1.2
date 93.06.11.16.15.25; author Rhialto; state Exp;
branches;
next 1.1;
1.1
date 93.06.11.15.19.27; author Rhialto; state Exp;
branches;
next ;
desc
@Code for opening, reading, writing the serial port
@
1.3
log
@Save on SDCMD_QUERY commands when not all available data is read.
@
text
@/* $Id: tty.c,v 1.2 1993/06/11 16:15:25 Rhialto Exp $
* $Log: tty.c,v $
* Revision 1.2 1993/06/11 16:15:25 Rhialto
* First real RCS checkin
*
*/
/*
This file is part of El Cheapo Fax.
(c) Copyright 1993 by Olaf 'Rhialto' Seibert.
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#define LIBRARIES_MATHFFP_H /* do not include! */
#include <exec/types.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include "c2proto.h"
#include "log.h"
#include "tty.h"
#include "write.h"
#include "read.h"
static int condition_tty(int fd);
struct IOExtSer *ior, *iow;
struct MsgPort *Port;
int fcstate;
/* termio fakes */
/*
* These flow-control related functions are just stubs, because
* we do RTS/CTS flow control. The modem must be in &K3 mode
* and serial.device in SERF_7WIRE mode for this to work,
*/
int tty_fc(fd, state)
int fd;
fc_state state;
{
log(L_DEBUG, "tty_fc state %d", state);
fcstate = state;
return 0;
}
int
tcflow(int fd, int mode)
{
log(L_DEBUG, "tcflow mode %s", mode==TCION ? "TCION" : "TCOOFF");
if (mode == TCION) { /* trust caller on flow control mode */
static char c = XON;
nwrite(fd, &c, 1);
}
/* if mode == TCOOFF stop output until XON received */
return 0;
}
int
ioctl(int fd, int command, int parameter)
{
log(L_DEBUG, "ioctl command %d parm %d (ignored)", command, parameter);
}
static int condition_tty(fd)
int fd;
{
WaitIO((struct IORequest *)iow);
iow->IOSer.io_Command = SDCMD_SETPARAMS;
iow->io_RBufLen = 8192;
iow->io_ExtFlags = 0;
iow->io_Baud = 19200;
iow->io_ReadLen = 8;
iow->io_WriteLen = 8;
iow->io_StopBits = 1;
iow->io_SerFlags &= ~(SERF_EOFMODE | SERF_PARTY_ON | SERF_PARTY_ODD);
iow->io_SerFlags |= SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
DoIO((struct IORequest *)iow);
iow->IOSer.io_Flags = IOF_QUICK;
if (iow->IOSer.io_Error) {
log(L_EMERG, "condition_tty: can't set attrs: %d", iow->IOSer.io_Error);
return -1;
}
}
int tty_open(filename)
char *filename;
{
int unit;
char *devicename;
log(L_DEBUG, "tty_open(%s)", filename);
/* 0/serial.device */
if (devicename = strchr(filename, '/')) {
devicename++;
unit = atoi(filename);
} else if ('0' <= filename[0] && filename[0] <= '9') {
devicename = "serial.device";
unit = atoi(filename);
} else {
devicename = filename;
unit = 0;
}
Port = CreatePort(NULL, 0);
if (Port == NULL) {
log(L_EMERG, "no MsgPort");
return -1;
}
iow = (struct IOExtSer *)CreateExtIO(Port, sizeof (*iow));
iow->IOSer.io_Flags = IOF_QUICK;
ior = (struct IOExtSer *)CreateExtIO(Port, sizeof (*ior));
if (ior == NULL || iow == NULL) {
log(L_EMERG, "no I/O requests");
tty_close(1);
return -1;
}
/* Should be O_NDELAY !! */
/* Should only be shared when we're being called from a front-door */
if (OpenDevice(devicename, unit, (struct IORequest *)iow, 0L)) {
iow->io_SerFlags = SERF_SHARED;
if (OpenDevice(devicename, unit, (struct IORequest *)iow, 0L)) {
log(L_EMERG, "can't open fax modem device: %d", iow->IOSer.io_Error);
tty_close(1);
return -1;
}
log(L_NOTICE, "opened serial port in shared mode");
}
if (condition_tty(1) < 0) {
tty_close(1);
return -1;
}
*ior = *iow;
return 1; /* fd will be ignored by us */
}
int tty_close(fd)
int fd;
{
if (iow) {
if (iow->IOSer.io_Device != 0 && (long) iow->IOSer.io_Device != -1)
CloseDevice((struct IORequest *)iow);
iow->IOSer.io_Device = 0;
DeleteExtIO((struct IORequest *)iow);
iow = NULL;
}
if (ior) {
DeleteExtIO((struct IORequest *)ior);
ior = NULL;
}
if (Port) {
DeletePort(Port);
Port = NULL;
}
return 0;
}
/* write.c */
unsigned char wbuf[256];
int nwrite(fd, buf, bufsize)
int fd;
char *buf;
int bufsize;
{
int done = bufsize;
if (WaitIO((struct IORequest *)iow)) {
iow->IOSer.io_Flags = IOF_QUICK;
log(L_EMERG, "do_write: previous write failed: %d", iow->IOSer.io_Error);
return -1;
}
iow->IOSer.io_Command = CMD_WRITE;
while (bufsize > sizeof(wbuf)) {
iow->IOSer.io_Data = buf;
iow->IOSer.io_Length = sizeof(wbuf);
DoIO((struct IORequest *)iow);
buf += sizeof(wbuf);
bufsize -= sizeof(wbuf);
}
memcpy(wbuf, buf, bufsize);
iow->IOSer.io_Data = wbuf;
iow->IOSer.io_Length = bufsize;
SendIO((struct IORequest *)iow);
return done;
}
int fdprintf(int fd, char *format, ...)
{
va_list ap;
char buf[1024];
va_start(ap, format);
vsprintf(buf, format, ap);
va_end(ap);
log(L_DEBUG, "fdprintf: %s", buf);
return (nwrite(fd, buf, strlen(buf)));
}
/* termio fakes */
int
tcflush(int fd, int ioctl)
{
log(L_DEBUG, "tcflush ioctl %d", ioctl);
if (ioctl & TCIFLUSH) {
ior->IOSer.io_Command = CMD_CLEAR;
DoIO((struct IORequest *)ior);
}
return 0;
}
int
tcdrain(int fd)
{
log(L_DEBUG, "tcdrain");
WaitIO((struct IORequest *)iow);
iow->IOSer.io_Flags = IOF_QUICK;
if (iow->IOSer.io_Error) {
log(L_EMERG, "tcdrain: previous write failed: %d", iow->IOSer.io_Error);
return -1;
}
return 0;
}
/* read.c */
static int timeout_init(void);
static void timeout_set(int seconds);
static int read_internal(int fd, char * buf, int bufsize);
struct timerequest *TimeOut;
int tmoinit;
static int timeout_init()
{
TimeOut = (struct timerequest *)CreateExtIO(Port, sizeof(*TimeOut));
if (TimeOut == NULL) {
log(L_EMERG, "no timerequest");
return -1;
}
if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)TimeOut, 0)) {
DeleteExtIO((struct IORequest *)TimeOut);
TimeOut = NULL;
log(L_EMERG, "no timer device");
return -1;
}
tmoinit = 1;
return 0;
}
static void timeout_set(seconds)
int seconds;
{
if (seconds) {
TimeOut->tr_node.io_Command = TR_ADDREQUEST;
TimeOut->tr_time.tv_secs = seconds;
TimeOut->tr_time.tv_micro = 0;
SendIO((struct IORequest *)TimeOut);
} else {
if (CheckIO((struct IORequest *)TimeOut) == 0) {
AbortIO((struct IORequest *)TimeOut);
}
WaitIO((struct IORequest *)TimeOut);
}
}
/*
* Like a normal read, except poll for input. Return -1 on error or
* 0 if no data is available.
*/
int pread(fd, buf, bufsize)
int fd;
char *buf;
int bufsize;
{
static int avail;
if (avail <= 0) {
ior->IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)ior);
avail = ior->IOSer.io_Actual;
}
if (avail > 0) {
if (avail < bufsize)
bufsize = avail;
avail -= bufsize;
ior->IOSer.io_Command = CMD_READ;
ior->IOSer.io_Data = buf;
ior->IOSer.io_Length = bufsize;
if (DoIO((struct IORequest *)ior) != 0) {
log(L_ERR, "pread read error");
return -1;
}
return (int)ior->IOSer.io_Actual;
}
return 0;
}
/* Original "documentation":
* Read from fd into a buf with maxlength bufsize. Return when
* a minimum of minsize bytes have been read. Wait a maximum
* of seconds seconds before timing out. Return 0 if a timeout
* occured. Return -1 if the read failed. In other cases,
* return the total bytes read.
*/
/* What the actual implementation did:
* Wait for the timeout, or data being available.
* If timeout, return 0.
* If data available, grab all of it (up to bufsize) and return amount.
*/
static int read_internal(fd, buf, bufsize)
int fd;
char *buf;
int bufsize;
{
int bytes;
long sigmask;
bytes = pread(fd, buf, bufsize);
if (bytes)
return bytes;
/* No data. Wait for something to happen. */
ior->IOSer.io_Command = CMD_READ;
ior->IOSer.io_Data = buf;
ior->IOSer.io_Length = 1;
SendIO((struct IORequest *)ior);
/* Wait for data or timeout. */
wait:
sigmask = Wait(1L << Port->mp_SigBit | SIGBREAKF_CTRL_C);
sigmask &= SIGBREAKF_CTRL_C;
/* Was it data? */
if (CheckIO((struct IORequest *)ior)) {
WaitIO((struct IORequest *)ior);
bytes = ior->IOSer.io_Actual;
if (bytes && bufsize > 1) {
bytes += pread(fd, buf + 1, bufsize - 1);
}
log(L_DEBUG, "got %d: \"%.*s\"", bytes, bytes, buf);
return bytes;
}
/* Not a false alarm? */
if (sigmask == 0 &&
CheckIO((struct IORequest *)TimeOut) == 0)
goto wait;
/* Nope - a timeout */
AbortIO((struct IORequest *)ior);
WaitIO((struct IORequest *)ior);
log(L_ERR, "read abort or timeout");
/* Maybe the abort didn't work */
return ior->IOSer.io_Actual > 0 ? ior->IOSer.io_Actual :
sigmask ? -1 : 0;
}
/*
* Like a normal read, except use a timeout. Returns the bytes
* that were read.
*
* Return codes:
* 0 timeout
* -1 failure, see errno for more information
*/
int tread(fd, buf, bufsize, timeout)
int fd;
char *buf;
int bufsize;
int timeout;
{
int bytes;
if (!tmoinit)
timeout_init();
timeout_set(timeout);
bytes = read_internal(fd, buf, bufsize);
timeout_set(0);
return (bytes);
}
/*
Read a string, terminated by a CR, into the buffer. Return the
length of characters read, include the CR. Skips any NL chars
that might be encountered, since they can safely be ignored.
Return codes:
0 timeout
-1 failure, see errno for more information
*/
int fdgets(fd, buf, bufsize)
int fd;
char *buf;
int bufsize;
{
char *bufp = buf;
int i;
for (i = 0; i < bufsize; i++) {
char c;
switch (read_internal(fd, &c, 1)) {
case 0:
return (0);
case 1:
if (c != '\n') {
*bufp++ = c;
if (c == '\r')
return (i+1);
}
break;
default:
return (-1);
}
}
return (i);
}
/*
* Read a line, until a NL, with default timeout. Return -1 on
* failure. Return 0 on timeout. Otherwise, return total bytes
* read;
*/
int tfdgets(fd, buf, bufsize, timeout)
int fd;
char *buf;
int bufsize;
int timeout;
{
int bytes;
if (!tmoinit)
timeout_init();
timeout_set(timeout);
bytes = fdgets(fd, buf, bufsize);
timeout_set(0);
return (bytes);
}
int wait_for_char(fd, c_expect, timeout)
int fd;
char c_expect;
int timeout;
{
if (!tmoinit)
timeout_init();
timeout_set(timeout);
log(L_DEBUG, "waiting %d seconds for char %d", timeout, c_expect);
for (;;) {
char c;
if (read_internal(fd, &c, 1) != 1) {
timeout_set(0);
return (-1);
}
if (c == c_expect)
return (0);
}
}
int wait_for_string(fd, s_expect, timeout)
int fd;
char *s_expect;
int timeout;
{
if (!tmoinit)
timeout_init();
timeout_set(timeout);
log(L_DEBUG, "waiting %d seconds for string %s", timeout, s_expect);
for (;;) {
char buf[BUFSIZ];
int bytes;
if ((bytes = fdgets(fd, buf, sizeof(buf))) <= 0) {
timeout_set(0);
return (-1);
}
if (bytes > 1) {
buf[bytes] = '\0';
if (strncmp(s_expect, buf, strlen(s_expect)) == 0)
return (0);
}
}
}
@
1.2
log
@First real RCS checkin
@
text
@d1 5
a5 2
/* $Id$
* $Log$
d307 1
a307 2
ior->IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)ior);
d309 5
a313 3
if (ior->IOSer.io_Actual > 0) {
if (ior->IOSer.io_Actual < bufsize)
bufsize = ior->IOSer.io_Actual;
d315 5
d327 1
d329 1
a329 1
return (int)ior->IOSer.io_Actual;
@
1.1
log
@Initial revision
@
text
@d1 3
d68 1
a68 1
log(L_DEBUG, "tcflow mode %d", mode);
d81 1
a81 1
log(L_DEBUG, "ioctl command %d parm %d", command, parameter);
d95 2
a96 1
iow->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE | SERF_7WIRE;
d140 1
d142 7
a148 3
log(L_EMERG, "can't open fax modem device: %d", iow->IOSer.io_Error);
tty_close(1);
return -1;
d157 1
a157 1
return 1; /* fd will be ignored */
a317 1
return (int)ior->IOSer.io_Actual;
d319 1
a319 1
return 0;
d376 1
a376 1
log(L_ERR, "read timeout");
@